(function () {
	'use strict';

	var request = require('request');
	var fs = require('fs');
	// var fsx = require('fs-extra');
	var http = require('http');
	var path = require('path');
	var del = require('del');
	var extract = require('extract-zip');
	var recursiveCopy = require('recursive-copy');
	var gui = require('nw.gui');
	var spawn = require('child_process').spawn;

	var platform = process.platform;
	platform = /^win/.test(platform) ? 'win' : /^darwin/.test(platform) ? 'mac' : 'linux' + (process.arch == 'ia32' ? '32' : '64');

	function Updater(options) {
		this.status = '';
		this.progress = '0%';

		this.options = {
			downloadFileName: 'app_new.zip',
			basePath: options.basePath,
			downloadPath: options.basePath,
			unpackPath: path.join(options.basePath, 'app_new'),
			copyFromPath: path.join(options.basePath, 'app_new'),
			copyToPath: path.join(options.basePath, 'app'),
			runAppPath: options.runAppPath
		};
	};

    /**
     * unpack starts
     */
	var pUnpack = {
        /**
         * @private
         */
		mac: function (filename, cb, manifest, temporaryDirectory) {
			var args = arguments,
				extension = path.extname(filename),
				destination = path.join(temporaryDirectory, path.basename(filename, extension));

			if (!fs.existsSync(destination)) {
				fs.mkdirSync(destination);
			}

			if (extension === ".zip") {
				exec('unzip -xo "' + filename + '" >/dev/null', { cwd: destination }, function (err) {
					if (err) {
						console.log(err);
						return cb(err);
					}
					var appPath = path.join(destination, getExecPathRelativeToPackage(manifest));
					cb(null, appPath);
				})

			}
			else if (extension === ".dmg") {
				// just in case if something was wrong during previous mount
				exec('hdiutil unmount /Volumes/' + path.basename(filename, '.dmg'), function (err) {
					// create a CDR from the DMG to bypass any steps which require user interaction
					var cdrPath = filename.replace(/.dmg$/, '.cdr');
					exec('hdiutil convert "' + filename + '" -format UDTO -o "' + cdrPath + '"', function (err) {
						exec('hdiutil attach "' + cdrPath + '" -nobrowse', function (err) {
							if (err) {
								if (err.code == 1) {
									pUnpack.mac.apply(this, args);
								}
								return cb(err);
							}
							findMountPoint(path.basename(filename, '.dmg'), cb);
						});
					});
				});

				function findMountPoint(dmg_name, callback) {
					exec('hdiutil info', function (err, stdout) {
						if (err) return callback(err);
						var results = stdout.split("\n");
						var dmgExp = new RegExp(dmg_name + '$');
						for (var i = 0, l = results.length; i < l; i++) {
							if (results[i].match(dmgExp)) {
								var mountPoint = results[i].split("\t").pop();
								var fileToRun = path.join(mountPoint, dmg_name + ".app");
								return callback(null, fileToRun);
							}
						}
						callback(Error("Mount point not found"));
					})
				}
			}
		},
        /**
         * @private
         */
		win: function (fileName, unpackPath, cb) {
			var unzip = function () {
				// unzip by C. Spieler (docs: https://www.mkssoftware.com/docs/man1/unzip.1.asp, issues: http://www.info-zip.org/)
				// exec( '"' + path.resolve(__dirname, 'tools/unzip.exe') + '" -u -o "' +
				//     filename + '" -d "' + unpackPath + '" > NUL', function(err){
				exec('"' + path.resolve(process.cwd(), 'node_modules/node-webkit-updater/app/tools/unzip.exe') + '" -u -o "' +
					'app_new.zip' + '" -d "' + unpackPath + '" > NUL', function (err) {
						if (err) {
							return cb(err);
						}

						cb(null);
					});
			};

			// fs.exists(unpackPath, function(exists){
			//     if(exists) {
			//         del(unpackPath, { force: true }, function (err) {
			//             if (err) {
			//                 cb(err);
			//             } else {
			//                 unzip();
			//             }
			//         });
			//     } else {
			//         unzip();
			//     }
			// });
			unzip();
		},
        /**
         * @private
         */
		linux32: function (filename, cb, manifest, temporaryDirectory) {
			//filename fix
			exec('tar -zxvf "' + filename + '" >/dev/null', { cwd: temporaryDirectory }, function (err) {
				console.log(arguments);
				if (err) {
					console.log(err);
					return cb(err);
				}
				cb(null, path.join(temporaryDirectory, getExecPathRelativeToPackage(manifest)));
			})
		}
	};
	pUnpack.linux64 = pUnpack.linux32;
    /**
     * unpack ends
     */

	Updater.prototype.isNewVersionExists = function (url, currentVersion) {

		return new Promise(function () {
			http.get(url, function (res) {
				res.on('data', function (chunk) {
					console.log('data -> chunk:', chunk);
				})

				res.on('close', function () {
					console.log('data -> close');
					resolve();
				});
			})
		}, function () {
			reject();
		});
	}

    /**
     * download new version zip file
     */
	Updater.prototype.download = function (url) {
		var self = this;
		self.status = 'download';
		console.info('download file \"', path.join(self.options.downloadPath, self.options.downloadFileName), '\"');
		return new Promise(function (resolve, reject) {
			var contentType = '';
			request.get(url)
				.on('response', function (res) {
					self.status = '100%';
					contentType = res.headers['content-type'];
				})
				.on('error', function (err) {
					reject(err);
				})
				.pipe(fs.createWriteStream(path.join(self.options.downloadPath, self.options.downloadFileName)))
				.on('close', function () {
					if (contentType.indexOf('application/zip') > -1) {
						resolve();
					} else {
						reject({ fileType: contentType });
					}
				});
		});
	}

    /**
     * unpack downloaded zip file
     */
	Updater.prototype.unpack = function (fileName) {
		var self = this;
		console.info('unpack file \"', path.join(self.options.downloadPath, self.options.downloadFileName), '\"');
		return new Promise(function (resolve, reject) {
            /*
            pUnpack[platform](path.join(self.options.downloadPath, self.options.downloadFileName), 
                self.options.unpackPath, function(err) {
                if (err) {
                    reject(err);
                } else {
                    resolve('unpack success');
                }
            });
            */
			extract(path.join(self.options.downloadPath, self.options.downloadFileName),
				{ dir: self.options.unpackPath },
				function (err) {
					if (err) {
						reject(err);
					} else {
						resolve();
					}
				}
			)
		});
	}

    /**
     * copy unpacked new version directory to app
     */
	Updater.prototype.copyDir = function () {
		var self = this;
		console.info('copy file from \"', self.options.copyFromPath, '\"', 'to \"', self.options.copyToPath, '\"');
		return new Promise(function (resolve, reject) {
			recursiveCopy(self.options.copyFromPath, self.options.copyToPath, { overwrite: true },
				function (err, results) {
					if (err) {
						reject(err);
					} else {
						resolve();
					}
				});
		});
	}

	var pRun = {
        /**
         * @private
         */
		mac: function (appPath, args, options) {
			//spawn
			if (args && args.length) {
				args = [appPath].concat('--args', args);
			} else {
				args = [appPath];
			}
			return run('open', args, options);
		},
        /**
         * @private
         */
		win: function (appPath, args, options, cb) {
			return run(appPath, args, options, cb);
		},
        /**
         * @private
         */
		linux32: function (appPath, args, options, cb) {
			var appExec = path.join(appPath, path.basename(this.getAppExec()));
			fs.chmodSync(appExec, 0755)
			if (!options) options = {};
			options.cwd = appPath;
			return run(appPath + "/" + path.basename(this.getAppExec()), args, options, cb);
		}
	};

	pRun.linux64 = pRun.linux32;

    /**
     * @private
     */
	function run(path, args, options) {
		var opts = {
			detached: true
		};
		for (var key in options) {
			opts[key] = options[key];
		}
		var sp = spawn(path, args, opts);
		sp.unref();
		// return sp;
	}

	Updater.prototype.restart = function (cb) {
		var self = this;

		// return pRun[platform].apply(this, self.options.runAppPath);
		// run(self.options.runAppPath);
		var sp = spawn(self.options.runAppPath, [self.options.basePath, self.options.runAppPath], {});
		sp.unref();
		cb();


	};

	// module.exports = Updater;
	window.Updater = Updater;
})();

(function () {
	'use strict';

	function Progress(options) {
		this.progress = 0;

		this.options = {
			isMax: false,
			progressMax: 95
		}

		if (options && options.progressMax) {
			this.options.progressMax = options.progressMax;
		}
	};

	Progress.prototype.init = function () {
		var self = this;
		self.progress = 0;
	};

	Progress.prototype.increase = function () {
		var self = this;

		var progress = parseInt(self.progress);

		if (progress < self.options.progressMax) {
			progress += Math.floor(Math.random() * 5);
		} else {
			self.options.isMax = true;
		}

		self.progress = progress;

		return {
			isMax: self.options.isMax,
			progress: progress + '%'
		};
	};

	window.Progress = Progress;
})();